2013-01-08 01:54:00
动态网页的历史非常悠久,可以追溯到上个世纪。就技术类型而言,主要有ASP、PHP、JSP三大派。笔者接触过ASP、PHP,遗憾的是几乎从未接触过JSP。偶就天生不是JAVA语系的。
后来,笔者稍微远离了一下Web开发,Web发生了翻天覆地的变化,css成了布局主流,ASP.NET冒出来了。这使得笔者不得不在2008、2009年间重新进入Web开发领域。然后,自认为已经跟上时代了,于是又稍微远离了Web开发。短短两三年,PHP几乎啥也没变,HTML基本未变(虽然冒出了个HTML5),但ASP.NET却发生了翻天覆地的变化:官方MVC框架的推出,使得ASP.NET再也不用使用很别扭的服务端控件了,将自由操控HTML的权利还给了开发者(然而,却剥夺了自由操控URL的权利)。
下面,笔者以写一个搜索引擎为例,带大家进入ASP MVC 框架的世界。
如下图,在VS2012中建立一个ASP.NET MVC4 Web Application:

然后选Basic吧:

试图引擎按默认选择Razor吧。
建好之后,我们将看到如下的项目结构:
其中Views放各种页面,Content放css啥的,Controllers放“控制器”代码,Models里放各种业务模型的数据结构定义。

这个MVC框架的一个越俎代庖的事情就是接管了URL路由。嗯,其实也蛮方便的,叫越俎代庖有点过了,仁者见仁智者见智吧。
打开RouteConfig.cs,我肯可以看到:
1public class RouteConfig
2{
3 public static void RegisterRoutes(RouteCollection routes)
4 {
5 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
6
7 routes.MapRoute(
8 name: "Default",
9 url: "{controller}/{action}/{id}",
10 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
11 );
12 }
13}
这里有个默认的路由。比如一段http://www.xxx.com/a/b/c/,按照这个route的解释,a就是controller的名字,b就是action的名字,c就是id的名字。如果访问http://www.xxx.com/a/,那么a是controller的名字,action和id未给出,就按照default中的设定,action为Index,id为空。
说到这里,还没解释action是啥,id是啥呢。按照我们很久以前的url规划习惯,经常有article.aspx?action=modify&id=1这样子的url,controller的概念就是这里的acticle.aspx,表示文章处理的页面/模块;action就是url的query string中的action,一个处理模块通常由多个功能,action参数告诉它现在需要处理什么;id含有通常是跟随action而定的,比如刚才的例子,id表示要处理哪篇文章。
我们规划搜索引擎的URL吧:
| 路径 | 页面内容 |
|---|---|
| / | 首页 |
| /keyword | 搜索结果页 |
于是我们可以将上面的路由代码改为:
1public class RouteConfig
2{
3 public static void RegisterRoutes(RouteCollection routes)
4 {
5 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
6
7 routes.MapRoute(
8 name: "HomePage",
9 url: "",
10 defaults: new { controller = "Home", action = "Index" }
11 );
12
13 routes.MapRoute(
14 name: "SearchResult",
15 url: "{keyword}",
16 defaults: new { controller = "Home", action = "Search", keyword = UrlParameter.Optional }
17 );
18 }
19}
注意,我们使用了一个名为Home的controler,以及名为Index、Search的两个action,Search这个action带参数keyword。
右键单击Controllers目录,选择Add=>Controller:

输入名字HomeController,选择模版类型为Empty MVC controller:

注意,必须使用这个名字!因为我们之前在URL路由中设置的Controller名字是Home。
建好后得到一个比较简单的代码,将其改造成如下的样子:
1public class HomeController : Controller
2{
3 //
4 // GET: /
5
6 public ActionResult Index()
7 {
8 return View();
9 }
10
11 //
12 // GET: /keyword
13
14 public ActionResult Search(string keyword)
15 {
16 return View();
17 }
18}
右键单击View目录,新建子目录Home(一定要与controller同名),然后右键单击Home目录,选择Add=>View:

名字改为Index,其余默认:

注意,必须为Index,与action保持同名。然后用同样方法建立一个Search页面。
到现在为止,我们的网站可以跑了!访问根目录:

访问搜索结果页面:

考虑到搜索结果中,controller处理后需要把结果传递给页面,我们建立一个model类来表示这个数据结构。右键单击Models目录,新建一个C#代码文件,定义如下类型:
1namespace SearchEngine.Models
2{
3 public class SearchResultItem
4 {
5 public string Title { get; set; }
6 public string Link { get; set; }
7 public string Description { get; set; }
8 }
9
10 public class SearchResult
11 {
12 public string Keyword { get; set; }
13 public List<SearchResultItem> Results { get; set; }
14 }
15}
改写controller中的Search方法,改成:
1public ActionResult Search(string keyword)
2{
3 if (keyword == null)
4 {
5 return RedirectToAction("Index");
6 }
7
8 Models.SearchResult result = new Models.SearchResult();
9 result.Keyword = keyword;
10 result.Results = new List<Models.SearchResultItem>();
11
12 for (int i = 0; i < 10; ++i)
13 {
14 Models.SearchResultItem item = new Models.SearchResultItem();
15 item.Link = "http://www.streamlet.org/";
16 item.Title = "溪流软件工作室";
17 item.Description = "快来访问溪流软件工作室!";
18
19 result.Results.Add(item);
20 }
21
22 return View(result);
23}
注意,我们建立了数据result,通过View(result)传递给页面。
改写Search.cshtml,改为:
1@model SearchEngine.Models.SearchResult
2@{
3 ViewBag.Title = "Search";
4}
5
6<h2>Search</h2>
7
8<p>搜索“@Model.Keyword”的结果:</p>
9
10@foreach (var item in Model.Results)
11{
12<p>
13 <a href="@item.Link" target="_blank">@item.Title</a><br />
14 @item.Description
15</p>
16}
第一行@model声明本页面的数据模型。后面@开头的都是C#语句,剩余的是HTML。大多数情况下,Razor能识别@的结束,这比<% %>、书写起来都简洁一点。
再访问一下搜索结果页:

这部分利用HTML的知识和PS功底即可。我这里简单的放了一个Logo和搜索框。首页代码如下:
1@{
2 ViewBag.Title = "世界第一搜索引擎";
3}
4
5@Styles.Render("~/Content/Index.css")
6
7@section scripts {
8 <script type="text/javascript">
9 var search = function ()
10 {
11 var keyword = $("#keyword").val();
12 window.location = "/" + keyword;
13 }
14 </script>
15}
16
17<br />
18<br />
19<br />
20<br />
21<br />
22<br />
23<br />
24
25<div id="searchBox">
26 <img src="~/Images/Logo.png" /><br />
27 <br />
28 <input id="keyword" type="text" />
29 <input id="submit" type="submit" value="搜索" onclick="javascript: search();" />
30</div>
页面效果如下:

搜索结果页面代码如下:
1@model SearchEngine.Models.SearchResult
2@{
3 ViewBag.Title = "Search";
4}
5
6@Styles.Render("~/Content/Search.css")
7
8@section scripts {
9 <script type="text/javascript">
10 var search = function ()
11 {
12 var keyword = $("#keyword").val();
13 window.location = "/" + keyword;
14 }
15 </script>
16}
17
18<div id="searchBox">
19 <a href="/"><img src="~/Images/Logo.png" /></a><br />
20 <input id="keyword" type="text" value="@Model.Keyword" />
21 <input id="submit" type="submit" value="搜索" onclick="javascript: search();" />
22</div>
23
24<br />
25
26@foreach (var item in Model.Results)
27{
28<p>
29 <a href="@item.Link" target="_blank">@item.Title</a><br />
30 @item.Description
31</p>
32}
页面效果如下:

目前,我们在Search方法中生成的数据是假的。实际情况中要根据实际结果来。当没有数据的时候,我们要给出友好提示。
因此,将controller中Search方法改为:
1public ActionResult Search(string keyword)
2{
3 if (keyword == null)
4 {
5 return RedirectToAction("Index");
6 }
7
8 Models.SearchResult result = new Models.SearchResult();
9 result.Keyword = keyword;
10 result.Results = new List<Models.SearchResultItem>();
11
12 //for (int i = 0; i < 10; ++i)
13 //{
14 // Models.SearchResultItem item = new Models.SearchResultItem();
15 // item.Link = "http://www.streamlet.org/";
16 // item.Title = "溪流软件工作室";
17 // item.Description = "快来访问溪流软件工作室!";
18
19 // result.Results.Add(item);
20 //}
21
22 return View(result);
23}
Search页面相应地改为:
1@model SearchEngine.Models.SearchResult
2@{
3 ViewBag.Title = "Search";
4}
5
6@Styles.Render("~/Content/Search.css")
7
8@section scripts {
9 <script type="text/javascript">
10 var search = function ()
11 {
12 var keyword = $("#keyword").val();
13 window.location = "/" + keyword;
14 }
15 </script>
16}
17
18<div id="searchBox">
19 <a href="/"><img src="~/Images/Logo.png" /></a><br />
20 <input id="keyword" type="text" value="@Model.Keyword" />
21 <input id="submit" type="submit" value="搜索" onclick="javascript: search();" />
22</div>
23
24<br />
25
26@if (Model.Results == null || Model.Results.Count() == 0)
27{
28 <strong>根据相关法律法规和政策,部分搜索结果未予显示。</strong>
29}
30else
31{
32 foreach (var item in Model.Results)
33 {
34<p>
35 <a href="@item.Link" target="_blank">@item.Title</a><br />
36 @item.Description
37</p>
38 }
39}
页面效果:

例子代码:http://pan.baidu.com/s/1o6r5Qga(SearchEngine.rar)
演示页面:http://www.streamlet.org/Search/
首发:http://www.cppblog.com/Streamlet/archive/2013/01/08/197092.html